package db.nio;

import sun.net.ConnectionResetException;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 通道信息
 * Created by daibin on 16-9-14.
 */
public class ChannelContext<T> {

    /**
     * 通道
     */
    private Framer framer;

    /**
     * 数据包装处理器
     */
    private Encoder<T> encoder;

    /**
     * 数据解析器
     */
    private Decoder<T> decoder;

    /**
     * 数据处理器
     */
    private Processor<T> processor;

    /**
     * 参数
     */
    private Map<Object,Object> parameter;


    /**
     * 读线程锁
     */
    private volatile boolean readWaite = false;

    /**
     * 写线程锁
     */
    private volatile boolean writeWaite = false;


    /**
     * 通道基础信息
     * @param channel
     * @param packHandler
     * @param parseHandler
     * @param processor
     */
    public ChannelContext(Framer channel, Encoder packHandler, Decoder parseHandler, Processor processor) {
        this.framer = channel;
        this.encoder = packHandler;
        this.decoder = parseHandler;
        this.processor = processor;
        this.parameter = new HashMap<Object,Object>();
    }



    /**
     * 写数据
     *
     * @param obj
     */
    public void write(T obj){
        while(writeWaite)
            continue;
        writeWaite = true;
        try {
            ByteBuffer buffer = encoder.encode(obj);
            framer.write(buffer);

        }catch (ConnectionResetException e){
            processor.doClose(this);
        }catch (Exception e){
            processor.doException(e,this);
        }finally {
            writeWaite = false;
        }
    }

    /**
     * 读数据
     * @return
     * @throws Exception
     */
    public List<T> read(){
        while (readWaite)
            continue;
        readWaite = true;
        try {
            List<ByteBuffer> byteBufferList = framer.read();
            if(byteBufferList != null && byteBufferList.size()>0){
                List<T> data = new ArrayList<T>(byteBufferList.size());
                for(ByteBuffer byteBuffer :byteBufferList){
                    try {
                        data.add(decoder.decode(byteBuffer));
                    }catch (Exception e){
                        processor.doException(e,this);
                    }
                }
                return data;
            }
        }catch (ConnectionResetException e){
            processor.doClose(this);
        } catch (Exception e) {
            processor.doException(e,this);
        } finally {
            readWaite = false;
        }
        return null;
    }


    /**
     * 关闭当前通道
     */
    public void close() {
        try {
            framer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置参数
     * @param key
     * @param value
     */
    public void set(Object key,Object value){
        this.parameter.put(key,value);
    }

    /**
     * 取参数
     * @param key
     * @param <V>
     * @return
     */
    public <V> V get(Object key){
       return (V) this.parameter.get(key);
    }

    public Framer getFramer(){
        return this.framer;
    }

    public void setFramer(Framer framer) {
        this.framer = framer;
    }

    public Encoder<T> getEncoder() {
        return encoder;
    }

    public void setEncoder(Encoder<T> encoder) {
        this.encoder = encoder;
    }

    public Decoder<T> getDecoder() {
        return decoder;
    }

    public void setDecoder(Decoder<T> decoder) {
        this.decoder = decoder;
    }

    public Processor<T> getProcessor() {
        return processor;
    }

    public void setProcessor(Processor<T> processor) {
        this.processor = processor;
    }
}
